package sg.techstudio.suntec.dao;

import java.util.Collection;
import java.util.Date;
import java.util.List;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.webflow.core.collection.SharedAttributeMap;

import sg.techstudio.suntec.filter.UserFilter;
import sg.techstudio.suntec.object.RoleObj;
import sg.techstudio.suntec.object.UserChangePasswordObj;
import sg.techstudio.suntec.object.UserObj;

@Repository("userDao")
@Transactional
public class UserDao {
	private static final Log log = LogFactory.getLog(UserDao.class);
	
	@Autowired
	private SessionFactory sessionFactory;
	
	public boolean authenticate(String username, String password) {
		log.debug("authenticate() entry");
		Session ses = sessionFactory.getCurrentSession();
		Criteria c = ses.createCriteria(UserObj.class);
		c.add(Restrictions.ilike("username", username));
		c.add(Restrictions.eq("password", hashPassword(password)));
		Object obj = c.uniqueResult();
		return obj!=null && obj instanceof UserObj;
	}
	
	public UserObj getUser(String username) {
		log.debug("getUser() entry");
		Criteria c = sessionFactory.getCurrentSession().createCriteria(UserObj.class);
		c.add(Restrictions.ilike("username", username));
		UserObj userObj = (UserObj)c.uniqueResult();
		return userObj;
	}
	
	public RoleObj getUserRole(String username) {
		log.debug("getUserRole() entry");
		Criteria c = sessionFactory.getCurrentSession().createCriteria(UserObj.class);
		c.add(Restrictions.ilike("username", username));
		UserObj userObj = (UserObj)c.uniqueResult();
		return userObj==null?null:userObj.getRole();
	}
	/*
	protected void traverseUser(Collection<UserObj> userObjCol) {
		log.debug("traverseUser(Col) entry");
		if(userObjCol==null||userObjCol.isEmpty())
			return;
		for(UserObj userObj: userObjCol)
			traverseUser(userObj);
	}
	
	protected UserObj traverseUser(UserObj userObj) {
		log.debug("traverseUser() entry");
		if(userObj!=null && userObj.getRole()!=null)
			log.debug("121210 rolename is "+userObj.getRole().getName());
		return userObj;
	}
	*/
	public void saveUser(UserObj user) {
		log.debug("saveUser() entry");
		Session ses = sessionFactory.getCurrentSession();
		user.setUpdatedDate(new Date());
		ses.saveOrUpdate(user);
	}
	
	protected String hashPassword(String password) {
		return DigestUtils.md5Hex(password);
	}
	
	public UserObj hashPassword(UserObj userObj) {
		if(userObj == null)
			return null;
		userObj.setPassword(hashPassword(userObj.getPassword()));
		return userObj;
	}
	
	public void saveUsers(Collection<UserObj> userCol) {
		log.debug("saveUsers() entry");
		if(userCol==null || userCol.isEmpty())
			return;
		Session ses = sessionFactory.getCurrentSession();
		for(UserObj u: userCol)
			ses.saveOrUpdate(u);
	}
	
	public void saveOrUpdateRole(RoleObj role) {
		log.debug("saveOrUpdateRole() entry");
		sessionFactory.getCurrentSession().saveOrUpdate(role);
	}
	
	public void changePassword(long id, UserChangePasswordObj userChangePasswordObj) {
		log.debug("changePassword() entry");
		UserObj u = getUser(id);
		u.setPassword(userChangePasswordObj.getNewPassword());
		saveUser(hashPassword(u));
	}
	
	public UserObj getUser(long id) {
		log.debug("getUser() entry");
		Session ses = sessionFactory.getCurrentSession();
		return (UserObj) ses.get(UserObj.class, id);
	}
	
	@SuppressWarnings("unchecked")
	public List<UserObj> getAllUser(){
		log.debug("getAllUser() entry");
		Criteria c = sessionFactory.getCurrentSession().createCriteria(UserObj.class);
		return c.list();
	}
	
	@SuppressWarnings("unchecked")
	public List<UserObj> getAllUserByFilter(UserFilter userFilter){
		log.debug("getAllUserByFilter() entry");
		Criteria c = sessionFactory.getCurrentSession().createCriteria(UserObj.class);
		if(userFilter!=null) {
			if(!StringUtils.isBlank(userFilter.getUsername()))
				c.add(Restrictions.ilike("username", "%"+userFilter.getUsername()+"%"));
			if(!StringUtils.isBlank(userFilter.getEmail()))
				c.add(Restrictions.ilike("email", "%"+userFilter.getEmail()+"%"));
		}
		c.setProjection(Projections.rowCount());
		userFilter.getPaging().setTotalResults((Long)c.uniqueResult());
		
		c.setProjection(null);
		c.setFirstResult(userFilter.getPaging().getFirstResult());
		c.setMaxResults(userFilter.getPaging().getMaxResults());
		if(!StringUtils.isBlank(userFilter.getOrdering().getOrderBy())) {
			c.addOrder(userFilter.getOrdering().isOrderAsc()?
					Order.asc(userFilter.getOrdering().getOrderBy())
					: Order.desc(userFilter.getOrdering().getOrderBy()));
		}
		List<UserObj> userList = c.list();
//		traverseUser(userList);
		return userList;
	}
	
	public void updateUserFilter(UserFilter userFilter, int noContent) {
		log.debug("updateUserFilter() entry");
		if(userFilter==null || noContent<=0)
			return;
		userFilter.setSelectedContentIds(new boolean[noContent]);
	}
	
	public UserObj selectUserObj(UserFilter userFilter, List<UserObj> userList) {
		log.debug("selectUserObj() entry");
		if(userList==null || userList.isEmpty() || userFilter==null)
			return new UserObj();
		int i=0;
		for(UserObj u: userList) {
			if(userFilter.getSelectedContentIds()[i++])
				return u;
		}
		return new UserObj();
	}
	
	public void deleteUsers(UserFilter userFilter, List<UserObj> userList) {
		log.debug("deleteUsers() entry");
		if(userList==null || userList.isEmpty() || userFilter==null)
			return;
		int i=0;
		Session ses = sessionFactory.getCurrentSession();
		for(UserObj u: userList) {
			if(userFilter.getSelectedContentIds()[i++])
				ses.delete(u);
		}
	}
	
	public void printRoleSession(SharedAttributeMap map) {
		log.debug("printRoleSession() entry");
		log.debug("121210 map="+map);
	}
}
